package ctf.evaluation.SimulatorTests;


import java.io.IOException;

import ctf.network.*;

import ctf.evaluation.Point;
import ctf.evaluation.TestCase;
import ctf.evaluation.simulator.*;
import ctf.evaluation.simulator.data.*;
import ctf.evaluation.simulator.responses.*;

import static ctf.model.Side.*;
import static ctf.evaluation.simulator.data.Player.State.*;


/** Tests player capture */
@SimulatorTest
public class TestCaptureClone extends TestCase
{
	/** Initialize the field with tree, flag and player locations. */
	public void setUp()
		throws IOException, NetworkException, ProtocolError
	{
		ConnectionManager.instance().enterState(ConnectionManager.STEALState.PLAY);

		red = ConnectionManager.instance().red();
		blue = ConnectionManager.instance().blue();
	}

	@Override public void tearDown() {}


	/** Test capturing a flag */
	public void	testFlagCapture()
		throws IOException, NetworkException, ProtocolError,
		       RoundOverException, GameOverException
	{
		// capture the red flag
		blue.sendLine("placePlayer 7 (250.0,125.0)");
		new CommandResponse(blue);

		blue.sendLine("accelerate 7 0 2.0");
		new CommandResponse(blue);

		State state;
		Player carrier;

		while(true)
		{
			sleep(SLEEP_TIME);
			blue.sendLine("getState");

			state = (new StateResponse(blue)).state();
			carrier = state.team(RIGHT).player(7);
			float x = carrier.location().x;

			if(x > 250.2)
				assertEquals("Blue 7 @ " + carrier.location(), 
				             DEFENDING, carrier.state());

			else if((x < 249.7) && (x > 125.3))
				assertEquals("Blue 7 @ " + carrier.location(),
				             ATTACKING, carrier.state());

			else if(x < 100)
			{
				assertEquals(
					"Blue 7 should've captured the flag by " + carrier.location()
					 + " - flag at (100,125)",
					FLAG_CARRIER, carrier.state());

				break;
			}
		}

		assertEquals(FLAG_CARRIER, carrier.state());
		assertEquals(0, state.team(LEFT).score());
		assertEquals(5, state.team(RIGHT).score());


		// stop!
		blue.sendLine("accelerate 7 0 -5.0");
		new CommandResponse(blue);

		while(true)
		{
			sleep(SLEEP_TIME);
			blue.sendLine("getState");

			state = (new StateResponse(blue)).state();
			if(state.team(RIGHT).player(7).speed() == 0) break;
		}

	}
	
	
	/** Collision between Attacker and Flag Carrier */
	public void	testAttackerFlagCarrierCollision()
		throws IOException, NetworkException, ProtocolError,
		       RoundOverException, GameOverException
	{
		testFlagCapture();

		blue.sendLine("placePlayer 5 (250.0,125.0)");
		new CommandResponse(blue);

		blue.sendLine("accelerate 5 0 2.0");
		new CommandResponse(blue);

		blue.sendLine("getState");
		State state = new StateResponse(blue).state();

		Player blue7 = state.team(RIGHT).player(7);
		
		while(true)
		{
			sleep(SLEEP_TIME);

			blue.sendLine("getState");
			state = new StateResponse(blue).state();

			Player blue5 = state.team(RIGHT).player(5);

			if(blue5.location().x <= (blue7.location().x + .45)) break;

			assertTrue("Blue 5 (@ " + blue5.location() + ") should be moving",
			           blue5.speed() > 0);
		}

		sleep(5*SLEEP_TIME);

		blue.sendLine("getState");
		state = new StateResponse(blue).state();

		Player blue5 = state.team(RIGHT).player(5);
		blue7 = state.team(RIGHT).player(7);

		assertClose("Blue 5 should be stopped", 0, blue5.speed());
		assertClose("Blue 7 should be stopped", 0, blue7.speed());

		assertEquals("Blue 5 should be Attacking", ATTACKING, blue5.state());
		assertEquals("Blue 7 should have the flag", FLAG_CARRIER, blue7.state());
	}
	
	
	
	


	/** How long to wait between "getState" requests (in ms) */
	protected static final int SLEEP_TIME = 100;

	/** Controller connections */
	protected ctf.network.tcp.Connection red, blue;
}
